#include <wx/wx.h>
#include <wx/ffile.h>
#include <wx/file.h>
#include <wx/wfstream.h>
#include <wx/zstream.h>

#include "pkginfo.h"
#include "mounttable.h"
#include "inibuilder.h"
#include "common.h"
#include "bzipstream.h"

/*const wxString& InstalledBuilder::get_installed_version(const wxString& version) {
	// HKEY_CURRENT_USER\Software\Cygnus Solutions\Cygwin\mounts v2\/etc
}*/

bool InstalledBuilder::parse_db(/* const wxString& path */) {
	MountTable& mt = MountTable::get();
	const wxString& path = mt.cygpath(CYGWIN_INSTALLED_DB_PATH);
	
	if ( false==wxFile::Exists(path) ) {
		return false;
	}
	
	 wxFFile dbfile(path);
	
	// init
	_installed_hash.clear();
	_packages.Clear();
	
	wxString name;
	wxString filename;
	wxString number;
	
	
	char buf[2048] = {0};
	int i = 1;
	char c = 'x';
	buf[0] = c;
	
	while (!dbfile.Eof()) {
		int flag = 0;
		
		// parse a line
		while (i<2048) {
			dbfile.Read(&c, 1);
			
			if (' '==c) {
				buf[i] = '\0';
				
				switch (flag) {
					case 0 : // package name
						name = wxString::FromAscii(buf);
						break;
					case 1 : // package file name
						filename = wxString::FromAscii(buf);
						break;
					default :
						break; // will never reach here
				}

				flag++;
				i = 0;
				continue; // read next char
			} else if ( ( '\n'==c || '\r'==c || dbfile.Eof() ) && strlen(buf)>0 ) { // line separator
				buf[i] = '\0';
				number = wxString::FromAscii(buf);
				i = 0;
				
				// extract version from filename
				wxString version = filename.Mid(name.Len()+1, filename.Len()-name.Len()-wxStrlen(_T(".tar.gz"))-2);
				InstalledInfo pkg_info;
				
				pkg_info.name = name;
				
				IniBuilder& inibuilder = IniBuilder::get();
				
				if ( version.Contains(_T("-src")) ) {
					version = version.Mid( 0, version.Len()-wxStrlen(_T("-src"))-1 );
					pkg_info.source_version = version;
					pkg_info.source_path = filename;

					if (version_compare(inibuilder.packages[name].version, version) > 0) {
						inibuilder.set_pkg_src_status(name, PkgInfo::OUTDATED);
					} else  {
						inibuilder.set_pkg_src_status(name, PkgInfo::UPDATED);
					}
				} else {
					pkg_info.binary_version = version;
					pkg_info.binary_path = filename;
					
					if (version_compare(inibuilder.packages[name].version, version) > 0) {
						inibuilder.set_pkg_status(name, PkgInfo::OUTDATED);
					} else  {
						inibuilder.set_pkg_status(name, PkgInfo::UPDATED);
					}
				}
				
				
				_installed_hash[name] = pkg_info;
				
				_packages.Add(name);
				
				buf[0] = '\0';
				break; // parse next line
			} else if (dbfile.Eof()) {
				break; // exit loop
			} else {
				buf[i] = c;
				i++;
			}
		} // end parse line
	}
	
	_packages.Sort();
	
	return true;
}


/* int InstalledBuilder::is_installed(const wxString& name) {
	if (_installed_hash.find(name) == _installed_hash.end() ) {
		return NOT_INSTALLED;
	}
	
	const wxString& binary_path = _installed_hash[name].binary_path;
	const wxString& source_path = _installed_hash[name].source_path;
	IniBuilder& inibuilder = IniBuilder::get();
	
	int flag = NOT_INSTALLED;
	
	if ( !binary_path.IsEmpty() ) { // binary installed
		if ( version_compare(inibuilder.packages[name].version, _installed_hash[name].binary_version) > 0 ) {
			flag = flag | BINARY_UPGRADABLE;
		} else {
			flag = flag | BINARY_INSTALLED;
		}
	}
	
	if ( !source_path.IsEmpty() ) {
		if ( version_compare(inibuilder.packages[name].version, _installed_hash[name].source_version) > 0 ) {
			flag = flag | SOURCE_UPGRADABLE;
		} else {
			flag = flag | SOURCE_INSTALLED;
		}
	}
	
	return flag;
}
*/


wxArrayString InstalledBuilder::get_installed_files(const wxString& pkg) {
	wxArrayString files;
	if (_installed_hash.find(pkg) == _installed_hash.end() ) {
		return files;
	}
	
	wxString lst_gz_path = MountTable::get().cygpath(CYGWIN_INSTALLED_LST_DIR);
	lst_gz_path.Append(pkg);
	lst_gz_path.Append(_T(".lst.gz"));
	
	if ( !wxFile::Exists(lst_gz_path) ) {
		return files;
	}
	
	wxFileInputStream temp_stream(lst_gz_path);
	wxZlibInputStream gz_stream(temp_stream);

	if ( !gz_stream.IsOk() ) {
		return files;
	}

	const int BUF_SIZE = 2048;
	char buf[BUF_SIZE] = {0};
	char c;
	int i = 0;
	
	while ( !gz_stream.Eof() && i<BUF_SIZE ) {
		c = gz_stream.GetC();
		
		if ( ( '\n'==c || '\r'==c || gz_stream.Eof() ) && strlen(buf)>0 ) { // line separator
			buf[i] = '\0';
			
			const wxString& path = wxString::FromAscii(buf);
			i = 0; // parse next line
			
			//if ( !path.EndsWith(_T("/")) ) {
				// wxString native = MountTable::get().cygpath(path);
			files.Add(path);
			//}
			
			buf[0] = '\0';
		} else {
			buf[i] = c;
			i++;
		}
	}
	
	return files;
}

bool InstalledBuilder::save_db() {
	wxString dbpath = MountTable::get().cygpath(_T("/etc/setup"));
	wxFileName::Mkdir(dbpath, 0777, wxPATH_MKDIR_FULL);
	dbpath.Append(_T("/installed.db"));
	
	wxFFile dbfile(dbpath, _T("w+b"));
	dbfile.Write(_T("INSTALLED.DB 2\n"));
	
	PkgHash& packages = IniBuilder::get().packages;
	PkgHash::iterator it;
	
	for (it=packages.begin(); it!=packages.end(); it++) {
		PkgInfo::STATUS status = it->second.binary_status;
		if ( status<=PkgInfo::AVAILABLE ) {
			continue
		}
		
		if ( status<=PkgInfo::AVAILABLE ) {
		const wxString& version = get_version(it->first);
		if ( version.IsEmpty() ) { // new install 
			
		}
		
		dbfile.Write()
	}
}

InstalledBuilder::InstalledBuilder() {}
InstalledBuilder::~InstalledBuilder() {}

InstalledBuilder InstalledBuilder::self;

